package process;

import java.io.*;
import java.nio.charset.Charset;

public class Demo {
    public static void main(String[] args) {
        try {
            /*
              cmd /c dir 是执行完dir命令后关闭命令窗口。
              cmd /k dir 是执行完dir命令后不关闭命令窗口。
              cmd /c start dir 会打开一个新窗口后执行dir指令，原窗口会关闭。
              cmd /k start dir 会打开一个新窗口后执行dir指令，原窗口不会关闭。
              可以用cmd /?查看帮助信息。

              注意：java中利用cmd执行的 bat 文件如果使用 utf-8 编码，弹出的cmd控制台中文会出现乱码。用ansi编码就没问题。
              而且用 cmd 命令执行 bat 文件了，一直会被阻塞。bat文件是可以直接被调用的。
              所以不要用cmd来执行bat！
            * */

            //如果考虑用cmd执行多条语句，应该改用bat，且bat中不要用pause，程序会被阻塞的。
            Runtime run = Runtime.getRuntime();
            Process process = run.exec("D:\\IT\\Java\\Spring\\Spring\\src\\com\\wanghua\\spring\\test\\process\\a.bat");
            p1(process);
            //p2(process);
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    /*
     * 有时候在java代码中会调用一些外部程序，比如SwfTools来转换swf、ffmpeg来转换视频等。
     * 如果你的代码这样写：Runtime.getRuntime().exec(command)，会发现程序一下就执行完毕，
     * 而在命令行里要执行一会，是因为java没有等待外部程序的执行完毕，此时就需要使用阻塞，
     * 来等待外部程序执行结果：
     * 对于一般的外部程序使用下面的阻塞代码就可以，至少pdf2swf.exe是没有问题的。
     * 但是紧接着又发现对于ffmpeg来说，以上代码会让程序卡住不动，需要使用另一种方式，封装成了一个方法 p2
     * */
    public static void p1(Process process) throws Exception {
        InputStream inputStream = process.getInputStream();
        InputStreamReader reader = new InputStreamReader(inputStream, Charset.forName("utf-8"));
        BufferedReader bufferedReader = new BufferedReader(reader);
        String line = null;
        while ((line = bufferedReader.readLine()) != null)  //有的bat在 readLine() 处会被阻塞
            System.out.println(line);
        int exitValue = process.waitFor();  //通过调用Process对象的waitFor()方法可以使主进程进入等待状态，直至子进程执行完毕，再进行下一步工作。如果对子进程处理不当，有可能造成主进程阻塞，整个程序死掉。

        bufferedReader.close();
        reader.close();
        inputStream.close();
    }

    @SuppressWarnings("static-access")
    public static int p2(Process process) throws Exception {
        InputStream in = null;
        InputStream err = null;
        int exitValue = -1; // process完成时的返回值
        try {
            in = process.getInputStream();
            err = process.getErrorStream();
            boolean finished = false; // process 完成时设为true
            while (!finished) {
                try {
                    while (in.available() > 0) {
                        // Print the output of our system call
                        Character c = new Character((char) in.read());
                        System.out.print(c);
                    }
                    while (err.available() > 0) {
                        // Print the output of our system call
                        Character c = new Character((char) err.read());
                        System.out.print(c);
                    }
                    //向process获取exitValue。如果process还没执行完成将抛出IllegalThreadStateException，如果完成了，finished变量设为true
                    exitValue = process.exitValue();
                    finished = true;
                } catch (IllegalThreadStateException e) {
                    Thread.currentThread().sleep(500); //如果Process还没有执行完成，小睡一会以节约CPU开销
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null)
                    in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (err != null) {
                try {
                    err.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return exitValue;
    }
}
